package cn.lx.sequence.strategy;

import cn.lx.sequence.properties.IdGeneratorProperties;
import cn.lx.sequence.service.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author lX
 * @version JDK 8
 * @className RedisIdGenerator (此处以class为例)
 * @date 2024/5/23
 * @description TODO
 */
@Component
@Slf4j
public class RedisIdGenerator implements IdGenerator {

    @Autowired
    IdGeneratorProperties idGeneratorProperties;

    @Autowired
    RedisTemplate redisTemplate;

    /**
     * 本地缓存
     */
    private final Map<String, Generator> generatorLocalCache = new ConcurrentHashMap<>();

    /**
     * 单机锁  同一台机器并发获取序列使用
     */
    private final ReadWriteLock lock = new ReentrantReadWriteLock(false);

    /**
     * 使用读写锁创建本地ID生成器对象,解决同一key重复创建。
     * @param seqName
     * @return
     */
    @Override
    public Long next(String seqName) {
        Generator idGenerator = null;
        //加一把读锁,看看当前序列是否已经有序列生成对象
        this.lock.readLock().lock();
        try {
            idGenerator = this.generatorLocalCache.get(seqName);
        } finally {
            this.lock.readLock().unlock();
        }
        if (idGenerator == null){
            this.lock.writeLock().lock();
            try {
                idGenerator = this.generatorLocalCache.get(seqName);
                if(idGenerator == null){
                    idGenerator = new Generator();
                    idGenerator.init(seqName, this.idGeneratorProperties.getStep(),redisTemplate);
                    this.generatorLocalCache.put(seqName, idGenerator);
                }
            }catch (Exception e) {
                log.error("获取ID生成器失败,异常信息:{}",e.getStackTrace());
                throw new RuntimeException("获取ID生成器失败,请检查!");
            } finally {
                this.lock.writeLock().unlock();
            }

        }

        return idGenerator.next();

    }

    @Override
    public synchronized List<Long> nextList(String seqName, int size) {
        Generator idGenerator = null;
        //加一把读锁,看看当前序列是否已经有序列生成对象
        this.lock.readLock().lock();
        try {
            idGenerator = this.generatorLocalCache.get(seqName);
        } finally {
            this.lock.readLock().unlock();
        }
        if (idGenerator == null){
            this.lock.writeLock().lock();
            try {
                idGenerator = this.generatorLocalCache.get(seqName);
                if(idGenerator == null){
                    idGenerator = new Generator();
                    idGenerator.init(seqName, this.idGeneratorProperties.getStep(),redisTemplate);
                    this.generatorLocalCache.put(seqName, idGenerator);
                }
            }catch (Exception e) {
                log.error("获取ID生成器失败,异常信息:{}",e.getStackTrace());
                throw new RuntimeException("获取ID生成器失败,请检查!");
            } finally {
                this.lock.writeLock().unlock();
            }

        }

        return idGenerator.nextList(size);

    }
}
